//
//  list.h
//  utilities
//
//  Created by Sam Jaffe on 9/15/12.
//  Copyright (c) 2012 Sam Jaffe. All rights reserved.
//

#pragma once

#include <memory>
#include <algorithm>
#include <cstddef>
#include <list>
#include <iterator>
#include <vector>
#include <initializer_list>
#include <functional>
#include <type_traits>

#pragma mark declarations

template <class Collection>
class limit_list : public Collection {
public:
    typedef limit_list<Collection> Self;
    typedef Collection Super;
    typedef typename Super::value_type value_type;
    typedef typename Super::allocator_type allocator_type;
    typedef typename Super::size_type size_type;
    typedef typename Super::difference_type difference_type;
    typedef typename Super::reference reference;
    typedef typename Super::const_reference const_reference;
    typedef typename Super::pointer pointer;
    typedef typename Super::const_pointer const_pointer;
    typedef typename Super::iterator iterator;
    typedef typename Super::const_iterator const_iterator;
    typedef typename Super::reverse_iterator reverse_iterator;
    typedef typename Super::reverse_iterator const_reverse_iterator;

private:
    const size_type max_size;
public:
    
    limit_list(size_type max_size)
    : max_size(max_size) {
        
    }
    
    template <class ...Args>
    limit_list(size_type max_size, Args&&... args)
    : Super(args...),
    max_size(max_size) {
        
    }
    
    ~limit_list() {}
    
    iterator insert(const_iterator pos, const_reference value) {
        if (full())
            return Super::end();
        else
            return Super::insert(pos, value);
    }
    
    iterator insert(const_iterator pos, value_type&& value) {
        if (full())
            return Super::end();
        else
            return Super::insert(pos, value);
    }
    
    iterator insert(const_iterator pos, size_type count, const_reference value) {
        if (max_size < (count + Super::size()))
            return Super::end();
        else
            return Super::insert(pos, count, value);
    }
    
    template <class InputIt>
    iterator insert(const_iterator pos, InputIt first, InputIt last) {
        auto it = first;
        for (; it != last; it++) {
            if (insert(pos++, *first) == Super::end())
                return Super::end();
        }
        return it;
    }
    
    iterator insert(const_iterator pos, std::initializer_list<value_type> ilist) {
        if (full())
            return Super::end();
        else
            return Super::insert(pos, ilist);
    }
    
    void push_back(value_type&& value) {
        if (!full())
            Super::push_back(value);
    }
    void push_front(value_type&& value) {
        if (!full())
            Super::push_front(value);
    }
    void push_back(const_reference value) {
        if (!full())
            Super::push_back(value);
    }
    
    void push_front(const_reference value) {
        if (!full())
            Super::push_front(value);
    }
    
    const size_type capacity() const {
        return max_size;
    }
    
    const bool full() const {
        return max_size == Super::size();
    }
};

template <class Collection, std::size_t Lim>
class bound_list : public limit_list<Collection> {
public:
    constexpr bound_list()
    : limit_list<Collection>(Lim) {
        
    }
    
    template <class... Args>
    bound_list(Args&&... args)
    : limit_list<Collection>(Lim, args...) {
        
    }
    
    ~bound_list() {
        
    }
};
